package com.kandinfo.base.security.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.kandinfo.base.admin.domain.WorkGroup;
import com.kandinfo.base.admin.repository.WorkGroupRepository;
import com.kandinfo.base.common.converter.ConverterService;
import com.kandinfo.base.common.dto.widget.DataTablesResponseDto;
import com.kandinfo.base.common.repository.AliasToBeanResultTransformerEx;
import com.kandinfo.base.common.service.AbstractService;
import com.kandinfo.base.common.util.Constants;
import com.kandinfo.base.security.domain.Role;
import com.kandinfo.base.security.domain.User;
import com.kandinfo.base.security.domain.UserRole;
import com.kandinfo.base.security.dto.UserDto;
import com.kandinfo.base.security.dto.UserSearchDto;
import com.kandinfo.base.security.repository.RoleRepository;
import com.kandinfo.base.security.repository.UserRepository;
import com.kandinfo.base.security.repository.UserRoleRepository;
import com.kandinfo.base.security.service.UserService;

@Service
public class UserServiceImpl extends AbstractService<User, Long, UserRepository> implements UserService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private UserRoleRepository userRoleRepository;
    @Autowired
    private WorkGroupRepository workGroupRepository;
    @Autowired
    private EntityManager entityManager;

    @Resource
    public void setUserRepository(UserRepository userRepository) {
        super.setRepository(userRepository);
    }

    @SuppressWarnings("unchecked")
    @Override
    public DataTablesResponseDto<UserDto> searchByCon(final UserSearchDto searchDto) {
        StringBuffer nativeSql = new StringBuffer(" select  distinct(u.id) id,u.name name,u.username username");
        nativeSql.append(",u.password password, u.status status,u.email email,u.mobile mobile");
        nativeSql.append(getSearchSql(searchDto));
        nativeSql.append(" LIMIT :start,:pageSize ");

        Query nativeQuery = entityManager.createNativeQuery(nativeSql.toString());
        setParameter(searchDto, nativeQuery);
        nativeQuery.setParameter("start", searchDto.getDisplayStart());
        nativeQuery.setParameter("pageSize", searchDto.getDisplayLength());
        org.hibernate.Query query = nativeQuery.unwrap(org.hibernate.Query.class);
        query.setResultTransformer(new AliasToBeanResultTransformerEx(User.class));
        DataTablesResponseDto<UserDto> responseDtoList = new DataTablesResponseDto<UserDto>();
        UserDto dto = null;
        List<User> users = query.list();
        List<UserDto> userDtoList = new ArrayList<UserDto>();
        for (User user : users) {
            Long userId = user.getId();
            StringBuffer roleName = new StringBuffer();
            String roleNameStr = "";
            String groupName = "";
            // 查找用户的角色
            List<UserRole> roleList = userRoleRepository.findByUserId(userId);
            if (roleList != null) {
                for (UserRole userRole : roleList) {
                    Long roleId = userRole.getRoleId();
                    Role role = roleRepository.findOne(roleId);
                    if (role != null) {
                        roleName.append(role.getRoleDesc() + ",");
                    }
                }
                roleNameStr = roleName.toString();
                if (roleNameStr.endsWith(",")) {
                    roleNameStr = roleNameStr.substring(0, roleNameStr.length() - 1);
                }
            }

            // 查找用户所在组
            List<WorkGroup> groupNameList = workGroupRepository.findGroupbyUserId(userId);
            if (!CollectionUtils.isEmpty(groupNameList)) {
                for (WorkGroup group : groupNameList) {
                    groupName += group.getName() + ",";
                }
                if (groupName.endsWith(",")) {
                    groupName = groupName.substring(0, groupName.length() - 1);
                }
            }
            dto = ConverterService.convert(user, UserDto.class);
            dto.setRoleName(roleNameStr);
            dto.setGroupName(groupName);

            userDtoList.add(dto);
        }
        responseDtoList.setEcho(searchDto.getEcho());
        responseDtoList.setData(userDtoList);
        Long recordCount = getRecordCount(searchDto);
        responseDtoList.setTotalDisplayRecords(recordCount);
        responseDtoList.setTotalRecords(recordCount);
        return responseDtoList;
    }

    private Long getRecordCount(UserSearchDto searchDto) {
        StringBuffer nativeSql = new StringBuffer("SELECT count(distinct(u.id)) ");
        nativeSql.append(getSearchSql(searchDto));
        Query nativeQuery = entityManager.createNativeQuery(nativeSql.toString());
        setParameter(searchDto, nativeQuery);
        return Long.parseLong(nativeQuery.getResultList().get(0).toString());
    }

    private Object getSearchSql(UserSearchDto searchDto) {
        StringBuffer nativeSql = new StringBuffer(" from user u ");
        if (searchDto != null) {
            if (searchDto.getRoleId() != null && searchDto.getGroupId() == null) {
                nativeSql.append(" ,user_role ur ");
                nativeSql.append(" where ur.user_id = u.id and ur.role_id =:roleId ");
            } else if (searchDto.getRoleId() == null && searchDto.getGroupId() != null) {
                nativeSql.append(" ,user_group ug ");
                nativeSql.append(" where ug.user_id = u.id and  ug.group_id =:groupId ");
            } else if (searchDto.getRoleId() != null && searchDto.getGroupId() != null) {
                nativeSql.append(" ,user_role ur ,user_group ug");
                nativeSql.append(
                        " where ur.user_id = u.id and ur.role_id =:roleId and ug.user_id = u.id and  ug.group_id =:groupId ");
            } else {
                nativeSql.append(" where 1=1");
            }

            if (StringUtils.isNotEmpty(searchDto.getName())) {
                nativeSql.append(" AND u.name like:name ");
            }
            if (StringUtils.isNotEmpty(searchDto.getUsername())) {
                nativeSql.append(" AND u.username like:username ");
            }
            if (StringUtils.isNotEmpty(searchDto.getStatus())) {
                nativeSql.append(" AND u.status =:status ");
            }

            // String[] sortInfo = searchDto.getOneSort();
            // if (sortInfo != null) {
            // String sortCol = sortInfo[0];
            // String sortDir = sortInfo[1];
            // String orderBy = " order by ";
            // if ("workStatus".equals(sortCol)) {
            // sortCol = "work_status";
            // }
            // if ("userNature".equals(sortCol)) {
            // sortCol = "user_nature";
            // }
            // orderBy += " u.";
            // nativeSql.append(orderBy);
            // nativeSql.append(sortCol);
            // nativeSql.append(" ");
            // nativeSql.append(sortDir);
            // }
        }
        return nativeSql.toString();
    }

    private void setParameter(UserSearchDto searchDto, Query nativeQuery) {
        if (searchDto != null) {
            if (StringUtils.isNotEmpty(searchDto.getName())) {
                nativeQuery.setParameter("name", "%" + searchDto.getName() + "%");
            }
            if (StringUtils.isNotEmpty(searchDto.getUsername())) {
                nativeQuery.setParameter("username", "%" + searchDto.getUsername() + "%");
            }
            if (StringUtils.isNotEmpty(searchDto.getStatus())) {
                nativeQuery.setParameter("status", searchDto.getStatus());
            }
            if (searchDto.getRoleId() != null) {
                nativeQuery.setParameter("roleId", searchDto.getRoleId());
            }
            if (searchDto.getGroupId() != null) {
                nativeQuery.setParameter("groupId", searchDto.getGroupId());
            }
        }

    }

    @Override
    public User saveUser(User user) {
        return userRepository.save(user);
    }

    @Override
    public String findUserNameById(Long id) {
        User user = userRepository.findUserById(id);
        return user.getUsername();
    }

    @Override
    public User findUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    public boolean isUserExisted(String username) {
        return userRepository.findByUsername(username) != null;
    }

    @Override
    public List<User> findByType(int type) {
        return userRepository.findByType(type);
    }

    @Override
    public User findUserById(Long id) {
        return userRepository.findOne(id);
    }

    @Override
    public void deleteUser(Long id) {
        User adminuser = findUserById(id);
        adminuser.setStatus(String.valueOf(Constants.USER_DELETE));
        userRepository.save(adminuser);
    }

    @Override
    public void reuseUser(Long id) {
        User adminuser = findUserById(id);
        adminuser.setStatus(String.valueOf(Constants.USER_ACTIVE));
        userRepository.save(adminuser);
    }

    @Override
    public List<User> findActiveUser() {
        return userRepository.findActiveUser(Constants.USER_ACTIVE);
    }

    @Override
    public List<User> searchPermsers(String permname) {
        return userRepository.searchPermsers(permname);
    }

    @Override
    public User findByUserNameAndMobile(String username, String mobile) {
        return userRepository.findByUserNameAndMobile(username, mobile);
    }
    
    @Override
    public List<User> getUsersBykey() {
        return userRepository.getUsersBykey();
    }
    
    @Override
    public Map<Long, User> getUserMap() {
        List<User> users = super.findAll();
        Map<Long, User> map = new HashMap<Long, User>();
        for (User user : users) {
            map.put(user.getId(), user);
        }
        return map;
    }

    @Override
    public List<User> findByUserType(Integer userType) {
        return userRepository.findByUserType(userType);
    }
}
